package com.nets.client;

import com.nets.decoder.PacketDecoder;
import com.nets.encoder.PacketEncoder;
import com.nets.packet.PacketI;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * @author sig
 * @since 2016/9/17
 */
public class Client {
    private String host;
    private int port;
    private EventLoopGroup group;
    private Bootstrap bootstrap;
    private Channel channel;

    public Client(String host, int port) {
        this.host = host;
        this.port = port;
        init();
    }

    public void init() {
        group = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .handler(new LoggingHandler(LogLevel.INFO))
                .handler(new ChannelInitializer() {

                    @Override
                    protected void initChannel(Channel channel)
                            throws Exception {
                        channel.pipeline()
                                .addLast(new LengthFieldBasedFrameDecoder(
                                        1024 * 1024, 0, 4, 0, 4))
                                .addLast("clientPacketDecoder", new PacketDecoder())
                                .addLast(new LengthFieldPrepender(4))
                                .addLast("clientPacketEncoder", new PacketEncoder());
                    }
                });
    }

    public void send(PacketI packet) throws Exception {
        if (connect()) channel.writeAndFlush(packet);
    }

    public synchronized boolean connect() throws Exception {
        if (null != channel && channel.isOpen()) return true;
        ChannelFuture future = bootstrap.connect(host, port).sync();
        channel = future.channel();
        return true;
    }

    public void shutdown() {
        if (null != group) group.shutdownGracefully();
    }
}
